/*
 * KKSprite.cpp
 *
 *  Created on: 2013-9-15
 *      Author: wanghua
 */

#include "KKSprite.h"
#include "KKDirector.h"
#include "XmlUtils.h"
#include "effects/CCGrid.h"

#include <iostream>

USING_NS_CC;

KKSprite::KKSprite() {

	this->m_animations = new KKSpriteAnimationDictionary();

	this->m_ccNode = this;
}

KKSprite::~KKSprite() {

	CC_SAFE_DELETE(m_animations);
}

KKSprite* KKSprite::spriteWithFile(const char *pszFileName) {
	KKSprite *pobSprite = new KKSprite();

	if (pobSprite && pobSprite->initWithFile(pszFileName)) {

		pobSprite->m_width = pobSprite->getContentSize().width;
		pobSprite->m_height = pobSprite->getContentSize().height;
		pobSprite->m_image = (new string(pszFileName))->c_str();
		;

		pobSprite->autorelease();

		return pobSprite;
	}
	CC_SAFE_DELETE(pobSprite);
	return NULL;
}

KKSprite* KKSprite::spriteWithTexture(CCTexture2D* texture) {
	KKSprite *pobSprite = new KKSprite();

	if (pobSprite && pobSprite->initWithTexture(texture)) {

		pobSprite->m_width = pobSprite->getContentSize().width;
		pobSprite->m_height = pobSprite->getContentSize().height;
		pobSprite->m_image.clear();
		;

		pobSprite->autorelease();

		return pobSprite;
	}
	CC_SAFE_DELETE(pobSprite);
	return NULL;
}

bool KKSprite::initCommonInfoWithXml(TiXmlElement* element, KKNode* parent) {

	if (this->initWithFile(element->Attribute("image"))) {

		ccTexParams paramsCaption = { GL_LINEAR, GL_LINEAR, GL_REPEAT,
		GL_REPEAT };

		this->getTexture()->setTexParameters(&paramsCaption);

		if (KKClipableNode::initCommonInfoWithXml(element, parent)) {

			return true;
		}
	}

	return false;
}

bool KKSprite::initDelayInfoWithXml(TiXmlElement* element) {

	if (KKClipableNode::initDelayInfoWithXml(element)) {
		TiXmlElement* animationElment = element->FirstChildElement("animation");

		int tagId = 1;

		while (animationElment != NULL) {

			KKSpriteAnimation* animation = KKSpriteAnimation::animationWithXml(
					animationElment);

			if (animation) {

				this->getAnimations()->setObject(animation,
						animation->getName());

				animation->setTag(tagId++);
			}

			animationElment = animationElment->NextSiblingElement("animation");

		}

		return true;
	}

	return false;
}

void KKSprite::saveToXml(TiXmlElement* element) {

	element->SetAttribute("class", "Sprite");

	KKClipableNode::saveToXml(element);

	if (m_animations->begin()) {
		KKSpriteAnimation* animation = m_animations->next();
		while (animation) {

			TiXmlElement* animationElement = new TiXmlElement("animation");

			animationElement->SetAttribute("name",
					animation->getName().c_str());

			KKSpriteFrame* frame = NULL;

			for (unsigned int j = 0; j < animation->getFrames()->count(); j++) {
				frame = animation->getFrames()->getObjectAtIndex(j);

				TiXmlElement* frameElement = new TiXmlElement("frame");

				frameElement->SetAttribute("image", frame->getImage().c_str());

				frameElement->SetDoubleAttribute("duration",
						frame->getDuration() * 1000);

				animationElement->LinkEndChild(frameElement);

			}

			element->LinkEndChild(animationElement);

			animation = m_animations->next();

		}
	}

}

void KKSprite::setDisplayFrame(CCSpriteFrame *pNewFrame) {

	CCSprite::setDisplayFrame(pNewFrame);

}

void KKSprite::setTextureFile(string pszFileName, bool assignImage,
		bool keepsize) {

	if (assignImage) {
		this->m_image = pszFileName;
	}

	CCTexture2D * texture = CCTextureCache::sharedTextureCache()->addImage(
			pszFileName.c_str());

	if (texture) {
		CCRect rect(0, 0, texture->getContentSize().width,
				texture->getContentSize().height);

		float scaledWidth = this->getScaledWidth();
		float scaleHeight = this->getScaledHeight();

		this->setDisplayFrame(CCSpriteFrame::createWithTexture(texture, rect));

		if (keepsize) {
			this->setScaleX(scaledWidth / this->getContentSize().width);
			this->setScaleY(scaleHeight / this->getContentSize().height);
		}

	}

}

void KKSprite::resetTexture() {

	setTextureFile(this->m_image);

}

void KKSprite::animate(float duration, const char* frameNames, ...) {

	this->stopActionByTag(KKSprite::ANIMATION_TAG);

	va_list args;

	va_start(args, frameNames);

	CCAnimation* pAnim = CCAnimation::create();

	const char* frameName = va_arg(args,const char*);

	if (frameNames) {
		pAnim->addSpriteFrameWithFileName(frameNames);
	}

	while (frameName) {
		pAnim->addSpriteFrameWithFileName(frameName);

		frameName = va_arg(args,const char*);
	}

	va_end(args);

	pAnim->setRestoreOriginalFrame(false);
	CCAction* action = this->runAction(CCAnimate::create(pAnim));
	//CCAnimate::actionWithDuration(ccTime(duration), pAnim, false));

	action->setTag(KKSprite::ANIMATION_TAG);
}

void KKSprite::animate(const char* animName, int loop, bool fill,
		CCObject* endTarget, SEL_CallFuncND endFunc, void* args, float delay) {

	this->stopActionByTag(KKSprite::ANIMATION_TAG);

	m_currentAnimationName = animName;

	if (KKDirector::isDebug) {
		CCLog("start animation %s %s loop=%d,fill=%d \n",
				this->getName().c_str(), animName, loop, fill);
	}

	CCAnimate* anim = getAnimation(animName, fill);

	if (anim) {
		CCFiniteTimeAction* action = anim;

		if (delay > 0) {
			action = CCSequence::create(anim, CCDelayTime::create(delay),
			NULL);
		}

		if (loop > 0) {
			action = CCRepeat::create(action, loop);
		} else if (loop == -1) {
			action = CCRepeatForever::create(
					dynamic_cast<CCActionInterval*>(action));
		}

		if (endTarget && endFunc) {
			action = CCSequence::create((CCFiniteTimeAction*) action,
					CCCallFuncND::create(endTarget, endFunc, args),
					NULL);
		}

		action->setTag(KKSprite::ANIMATION_TAG);

		this->runAction(action);
	}

}

CCAnimate* KKSprite::getAnimation(const char* animName, bool fill) {

	KKSpriteAnimation* animation = this->m_animations->objectForKey(animName);

	if (animation && animation->getFrames()->count() > 0) {
		CCAnimation* pAnim = CCAnimation::create();

		KKSpriteFrameArray::CCMutableArrayIterator it =
				animation->getFrames()->begin();

		KKSpriteFrame* frame = NULL;

		float deplay = 0.1;

		while (it != animation->getFrames()->end()) {
			frame = (KKSpriteFrame*) (*it);

			deplay = ((float) frame->getDuration());

			pAnim->addSpriteFrameWithFileName(frame->getImage().c_str());

			it++;
		}

		pAnim->setDelayPerUnit(deplay);

		pAnim->setRestoreOriginalFrame(!fill);
		CCAnimate* action = CCAnimate::create(pAnim);
//		actionWithAnimation(pAnim, !fill);

		action->setTag(KKSprite::ANIMATION_TAG);

		return action;
	}

	return NULL;

}

void KKSprite::setIsVisible(bool isVisible) {

	if (isVisible) {
		if (!this->m_isLoaded) {
			this->loadNode();
		}

		if (isVisible != this->getIsVisible()) {
			this->performEvent("onshow", NULL);
		}
	} else {
		if (isVisible != this->getIsVisible()) {
			this->performEvent("onhide", NULL);
		}
	}

	CCSprite::setVisible(isVisible);

}

void KKSprite::setOpacity(GLubyte opacity) {
	CCSprite::setOpacity(opacity);

	KKNodeArray::CCMutableArrayIterator it = m_objects->begin();

	CCRGBAProtocol* child = NULL;

	while (it != m_objects->end()) {
		child = dynamic_cast<CCRGBAProtocol*>(*it);

		if (child) {
			child->setOpacity(opacity);
		}
		it++;
	}

	if (this->m_bgColor) {
		this->m_bgColor->setOpacity(opacity);
	}
}

void KKSprite::onEnter() {
	CCSprite::onEnter();

	this->performEvent("onenter", NULL);

	if (this->isPhysics() && this->m_body == NULL) {

		int group = this->getIntProperty("group", 1);

		KKScene* curScene = KKDirector::shareDirector()->getCurrentScene();

		curScene->createBody(this, group);

		m_body->SetActive(this->getIsVisible());
	}

}

void KKSprite::onExit() {
	CCSprite::onExit();
	this->performEvent("onexit", NULL);

	if (this->isPhysics() && this->m_body) {
		KKScene* mapLayer = KKDirector::shareDirector()->getCurrentScene();
		mapLayer->destroyBody(this);
	}
}

void KKSprite::onDown(const KKTouch& touch) {

	KKNode::onDown(touch);

	if (!m_hotImage.empty()) {
		this->setTextureFile(this->m_hotImage.c_str(), false);
	}

}

void KKSprite::onUp(const KKTouch& touch) {

	KKNode::onUp(touch);

	if (!this->getSelected() && !this->m_image.empty()) {
		this->setTextureFile(this->m_image.c_str(), false);
	}

}

void KKSprite::setSelected(bool selected) {

	KKNode::setSelected(selected);

	if (selected) {

		if (!m_hotImage.empty()) {

			this->setTextureFile(m_hotImage, false);

		}

	} else {

		resetTexture();
	}

}

void KKSprite::setIsEnable(bool enabled) {

	KKNode::setIsEnable(enabled);

	if (!enabled) {

		if (!m_disableImage.empty()) {
			this->setTextureFile(m_disableImage, false);
		}

	} else {
		resetTexture();
	}

}

void KKSprite::visit() {

	if (!m_bVisible) {
		return;
	}
	glPushMatrix();

	/*	if (m_pGrid && m_pGrid->isActive()) {
	 m_pGrid->beforeDraw();
	 this->transformAncestors();
	 }*/

	this->transform();

	int test;

	float box[5];

	KKClipableNode::beginClip(test, box);

	CCNode* pNode = NULL;
	unsigned int i = 0;

	if (m_pChildren && m_pChildren->count() > 0) {
		// draw children zOrder < 0
		ccArray *arrayData = m_pChildren->data;
		for (; i < arrayData->num; i++) {
			pNode = (CCNode*) arrayData->arr[i];

			if (pNode && pNode->getZOrder() < 0) {
				pNode->visit();
			} else {
				break;
			}
		}
	}

	// self draw
	this->draw();

	// draw children zOrder >= 0
	if (m_pChildren && m_pChildren->count() > 0) {
		ccArray *arrayData = m_pChildren->data;
		for (; i < arrayData->num; i++) {
			pNode = (CCNode*) arrayData->arr[i];
			if (pNode) {
				pNode->visit();
			}
		}
	}

	KKClipableNode::endClip(test, box);

	/*	if (m_pGrid && m_pGrid->isActive()) {
	 m_pGrid->afterDraw(this);
	 }*/

	glPopMatrix();

}
